const keypress = require("keypress");
const { warn, getPrint, stdout, setLastError } = require("../utils/log_tool");
const {
    convert,
    flatten,
    removeDuplicate,
} = require("../utils/transform_tool");
const { parse, get_full_path, write_with_type } = require("../utils/file_tool");

const { eval_code } = require("./share_data");

keypress(process.stdin);

const { shareData, getDataByKey } = require("./share_data");

const PROCESS_STATE = {
    NONE: 0,
    CONTINUE: 1,
    BREAK: 2,
};

class BaseCommand {
    constructor(type, globalData, execSingle, exec) {
        this.type = type;
        this.selfData = null;
        this.shareData = shareData;
        this.globalData = globalData;
        this.execSingle = execSingle;
        this.exec = exec;
    }

    async willExecute() {
        return true;
    }

    async didExecute() {}

    async checkValid(commandCfg) {
        const conditionCode = commandCfg.when;
        const when_tip = commandCfg.when_tip;
        const cfgData = commandCfg.data;
        if (conditionCode) {
            const willExec = eval_code(conditionCode);
            if (!willExec) {
                when_tip && warn(`[${when_tip}]`);
                return;
            }
        }
        // 如果可选， 则要判断是否store_key是否已经有值
        const if_false = commandCfg.if_false;
        if (if_false) {
            const checkKey =
                typeof if_false === "string" ? if_false : cfgData?.store_key;
            if (checkKey && this.getDataByKey(checkKey)) {
                // warn(`${checkKey} 不为空， 跳过执行`)
                return;
            }
        }
        const if_true = commandCfg.if_true;
        if (if_true) {
            const checkKey =
                typeof if_true === "string" ? if_true : cfgData?.store_key;
            if (checkKey && !this.getDataByKey(checkKey)) {
                // warn(`${checkKey} 为空， 跳过执行`)
                return;
            }
        }
        const optional = commandCfg.optional;
        if (optional) {
            const options = ["Yes", "No"];
            warn(`\n是否执行 ${commandCfg.title || commandCfg.type}?`);
            await this.forward("select", {
                content: options,
                store_key: "$checkValidOptional",
            });
            if (options.indexOf(shareData.$checkValidOptional) === 1) {
                return;
            }
        }
        return true;
    }

    async handle(commandCfg, content, depth = 0) {
        /** @type {{type: string, title?: string, when:?: string, data: any, ignore_error: boolean, data_print: boolean, data_confirm: boolean}} */
        this.selfCfg = commandCfg;
        this.selfData = commandCfg.data;
        /** @type {string} */
        this.content = content;
        this.depth = depth || 0;

        // 判断参数是否存在
        const requiredParams = this.getRequiredParams();
        let failed = false;
        for (let index = 0; index < requiredParams.length; index++) {
            const key = requiredParams[index];
            const ret = getDataByKey(key, this.selfData);
            if (ret == null) {
                failed = true;
                warn(`\n缺少 ${key}`);
            }
        }
        if (failed) {
            throw `参数校验失败，请检查所有缺少的参数 ${getPrint(this.selfCfg, true)}`;
        }

        let ret;
        const data = this.selfData;
        const willExec = await this.willExecute();
        if (!willExec) {
            warn("\n不执行");
            return;
        }
        // 打印完整 data
        if (this.selfCfg.data_print) {
            await this.forward("print", {
                content: data,
                mode: "content",
                level: 3,
            });
        }
        // 确认完整 data
        if (this.selfCfg.data_confirm) {
            await this.forward("confirm", { content: data, mode: "content" });
        }
        if (data) {
            // 内容打印
            if (data.content_print) {
                await this.forward("print", {
                    content: this.content,
                    mode: "content",
                    level: 3,
                });
            }
            // 内容确认
            if (data.content_confirm) {
                await this.forward("confirm", {
                    content: this.content,
                    mode: "content",
                });
            }
        }

        ret = await this.execute();
        await this.didExecute();
        if (data) {
            ////// 数据预处理 BEG
            // 对结果进行语法解析
            if (data.parse_type) {
                try {
                    ret = await parse(ret, data.parse_type, data.parse_options);
                } catch (err) {
                    setLastError(
                        `parse ${ret} ${data.parse_type} error ${err.message}`,
                    );
                    ret = null;
                }
            }
            // 类型转换
            if (data?.value_type) {
                ret = convert(ret, data.value_type);
            }
            // 数组处理
            if (Array.isArray(ret)) {
                // 扁平处理
                if (data.flatten) {
                    ret = flatten(ret);
                }
                // 数据除重
                if (data.remove_duplicate) {
                    ret = removeDuplicate(ret, data);
                }
                // 数据排序
                if (data.store_sort) {
                    ret.sort();
                }
            }
            // 字符串类型处理
            if (typeof ret === "string") {
                if (data.store_trim) {
                    ret = ret.trim();
                }
            }
            ////// 数据预处理 END

            // 默认值
            if (!ret && data.default_value != null) {
                ret = data.default_value;
            }
            // 保存到共享数据
            if (data.store_key) {
                const keys = Array.isArray(data.store_key)
                    ? data.store_key
                    : data.store_key.split(".");
                let dst = this.shareData;
                const len = keys.length;
                let key;
                const store_key_type = data.store_key_type;
                for (let i = 0; i < len - 1; i++) {
                    key = keys[i];
                    // 键转换
                    switch (store_key_type?.[i]) {
                        case "eval":
                            key = eval_code(key);
                            break;
                    }
                    if (!dst[key]) {
                        dst[key] = {};
                    }
                    dst = dst[key];
                }
                key = keys[len - 1];
                const store_mode = data.store_mode || "default";
                switch (store_mode) {
                    case "push": {
                        if (!dst[key]) {
                            dst[key] = [];
                        }
                        dst = dst[key];
                        dst.push(ret);
                        break;
                    }
                    case "unshift": {
                        if (!dst[key]) {
                            dst[key] = [];
                        }
                        dst = dst[key];
                        dst.unshift(ret);
                        break;
                    }
                    case "append": {
                        if (dst[key] == null) {
                            dst[key] = "";
                        }
                        dst[key] += ret;
                        break;
                    }
                    case "merge": {
                        dst[key] = Object.assign({}, dst[key], ret);
                        break;
                    }
                    case "concat": {
                        if (!dst[key]) {
                            dst[key] = [];
                        }
                        dst[key] = dst[key].concat(ret);
                        break;
                    }
                    case "default": {
                        dst[key] = ret;
                        break;
                    }
                    default: {
                        throw `未实现的store_mode ${store_mode}`;
                        break;
                    }
                }
            }
            // 保存到store_dst目标
            if (data.store_dst) {
                const store_dst = get_full_path(data.store_dst);
                const store_dst_type = data.store_dst_type;
                await write_with_type(ret, store_dst, store_dst_type);
                if (data.reveal_dst) {
                    await this.forward("reveal", { src: store_dst });
                }
                if (data.open_dst) {
                    await this.forward("open", { src: store_dst });
                }
            }
            // if (data.key && !data.store_key && !data.store_dst && ret != undefined) {
            //     warn(`返回值未存储 ${getPrint(this.selfCfg, true)}`);
            // }
            // 数据映射
            if (data.mapping) {
                if (typeof data.mapping === "boolean") {
                    for (const k in ret) {
                        this.shareData[k] = ret[k];
                    }
                } else {
                    for (let i = 0; i < data.mapping.length; i++) {
                        const k = data.mapping[i];
                        this.shareData[k] = ret[i];
                    }
                }
            }
            // 参数打印
            if (data.store_print) {
                await this.forward("print", {
                    content: ret,
                    mode: "content",
                    level: data.store_print_level ?? 3,
                });
            }
            // 参数确认
            if (data.store_confirm) {
                await this.forward("confirm", {
                    content: ret,
                    mode: "content",
                });
            }
            // 参数写入标准输出stdout，需要配合参数 --LOG_LEVEL 99
            if (data.store_stdout) {
                stdout(ret);
            }
            // 写入剪切板
            if (data.store_clipboard) {
                await this.forward("write_clipboard", { content: ret });
            }
            // 数据校验
            if (data.store_validator) {
                const [ok, errmsg] = eval_code(data.store_validator)(ret);
                if (!ok) {
                    setLastError(errmsg || "校验失败");
                }
            }
        }
        // 写日志
        if (this.selfCfg.log !== undefined) {
            await this.forward("log", { content: this.selfCfg.log });
        }
        if (this.selfCfg.required && ret == null) {
            throw `执行结果不能为空`;
        }
        return ret;
    }

    async execute() {}

    /**
     * 转交给另外一个类型的命令处理
     * @param {*} type
     */
    async forward(type, data = this.selfData) {
        return await this.execSingle(
            {
                type: type,
                // 传递 ignore_error
                ignore_error: this.selfCfg.ignore_error,
                data: data,
            },
            this.depth,
        );
    }

    /**
     * 是否需要传入content
     */
    getRequireContent() {
        return false;
    }

    getDataByKey() {
        return getDataByKey.apply(this, arguments);
    }

    /**
     * 需要提供的参数
     */
    getRequiredParams() {
        return [];
    }

    /**
     * 设置执行状态
     * @param {*} state
     */
    setProcessState(state) {
        this.globalData.process_state = state;
    }

    /**
     * 重置执行状态
     */
    resetProcessState() {
        this.globalData.process_state = PROCESS_STATE.NONE;
    }

    /**
     * 是否为全自动
     * @returns
     */
    isFullAutomatic() {
        return this.shareData.FULL_AUTOMATIC;
    }
}

module.exports = {
    BaseCommand,
    PROCESS_STATE,
};
